/*
 * Copyright (c) 2010-2013 Ruben Chakhmakhchyan. All rights reserved.
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Eclipse Public License
 * Version 1.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://opensource.org/licenses/EPL-1.0 and read it before using this file.
 */

#include "scripting.h"
#include "plugin_model.h"
#include "plugin_impl.h"


bool ScriptableDeviceCapability::construct( const NPVariant *args, uint32_t argCount, NPVariant *result )
{
    NPObject *obj = NPN_CreateObject( m_npp, GET_NPOBJECT_CLASS( ScriptableDeviceCapability ) );
    if ( !obj )
        return false;

    OBJECT_TO_NPVARIANT( obj, *result );

    return true;
}

bool ScriptableDeviceCapability::hasProperty( NPIdentifier name )
{
    return name == npid.cap || name == npid.type || name == npid.valueType || name == npid.count 
        || name == npid.min || name == npid.max || name == npid.step || name == npid.currentValue || name == npid.defaultValue
        || name == npid.currentIndex || name == npid.defaultIndex
        || name == npid.item || name == npid.value || name == npid.items || name == npid.values;
}

bool ScriptableDeviceCapability::getProperty( NPIdentifier name, NPVariant *result )
{
    NPVariant& resultValue = *result;
    VOID_TO_NPVARIANT( *result );

    if ( !m_cap )
    {
        return false;
    }

    if ( name == npid.cap )
    {
        INT32_TO_NPVARIANT( m_cap->cap, *result );
    }
    else if ( name == npid.type )
    {
        INT32_TO_NPVARIANT( ( int32_t ) m_cap->type, *result );
    }
    else if ( name == npid.valueType )
    {
        INT32_TO_NPVARIANT( ( int32_t ) m_cap->valueType, *result );
    }
    else if ( name == npid.count )
    {
        if ( m_cap->type == CapType::List )
        {
            ListBaseCap* listCap = ( ListBaseCap* ) m_cap;
            INT32_TO_NPVARIANT( listCap->count, *result );
        }
        else
            return false;
    }
    else if ( name == npid.defaultIndex )
    {
        if ( m_cap->type == CapType::List )
        {
            ListBaseCap* listCap = ( ListBaseCap* ) m_cap;
            INT32_TO_NPVARIANT( listCap->defaultIndex, *result );
        }
        else
            return false;
    }
    else if ( name == npid.currentIndex )
    {
        if ( m_cap->type == CapType::List )
        {
            ListBaseCap* listCap = ( ListBaseCap* ) m_cap;
            INT32_TO_NPVARIANT( listCap->currentIndex, *result );
        }
        else
            return false;
    }
    else if ( name == npid.min )
    {
        if ( m_cap->type == CapType::Range )
        {
            switch ( m_cap->valueType )
            {
            case CapValueType::Int:
                {
                    IntRangeCap* rangeCap = ( IntRangeCap* ) m_cap;
                    INT32_TO_NPVARIANT( rangeCap->minValue, *result );
                }
                break;
            case CapValueType::Float:
                {
                    FloatRangeCap* rangeCap = ( FloatRangeCap* ) m_cap;
                    DOUBLE_TO_NPVARIANT( ( ( double ) rangeCap->minValue ), *result );
                }
                break;
            }
        }
        else
            return false;
    }
    else if ( name == npid.max )
    {
        if ( m_cap->type == CapType::Range )
        {
            switch ( m_cap->valueType )
            {
            case CapValueType::Int:
                {
                    IntRangeCap* rangeCap = ( IntRangeCap* ) m_cap;
                    INT32_TO_NPVARIANT( rangeCap->maxValue, *result );
                }
                break;
            case CapValueType::Float:
                {
                    FloatRangeCap* rangeCap = ( FloatRangeCap* ) m_cap;
                    DOUBLE_TO_NPVARIANT( ( ( double ) rangeCap->maxValue ), *result );
                }
                break;
            }
        }
        else
            return false;
    }
    else if ( name == npid.step )
    {
        if ( m_cap->type == CapType::Range )
        {
            switch ( m_cap->valueType )
            {
            case CapValueType::Int:
                {
                    IntRangeCap* rangeCap = ( IntRangeCap* ) m_cap;
                    INT32_TO_NPVARIANT( rangeCap->stepValue, *result );
                }
                break;
            case CapValueType::Float:
                {
                    FloatRangeCap* rangeCap = ( FloatRangeCap* ) m_cap;
                    DOUBLE_TO_NPVARIANT( ( ( double ) rangeCap->stepValue ), *result );
                }
                break;
            }
        }
        else
            return false;
    }
    else if ( name == npid.defaultValue )
    {
        if ( m_cap->type == CapType::Range )
        {
            switch ( m_cap->valueType )
            {
            case CapValueType::Int:
                {
                    IntRangeCap* rangeCap = ( IntRangeCap* ) m_cap;
                    INT32_TO_NPVARIANT( rangeCap->defaultValue, *result );
                }
                break;
            case CapValueType::Float:
                {
                    FloatRangeCap* rangeCap = ( FloatRangeCap* ) m_cap;
                    DOUBLE_TO_NPVARIANT( ( ( double ) rangeCap->defaultValue ), *result );
                }
                break;
            }
        }
        else
            return false;
    }
    else if ( name == npid.currentValue )
    {
        if ( m_cap->type == CapType::Range )
        {
            switch ( m_cap->valueType )
            {
            case CapValueType::Int:
                {
                    IntRangeCap* rangeCap = ( IntRangeCap* ) m_cap;
                    INT32_TO_NPVARIANT( rangeCap->currentValue, *result );
                }
                break;
            case CapValueType::Float:
                {
                    FloatRangeCap* rangeCap = ( FloatRangeCap* ) m_cap;
                    DOUBLE_TO_NPVARIANT( ( ( double ) rangeCap->currentValue ), *result );
                }
                break;
            }
        }
        else
            return false;
    }
    else if ( name == npid.currentIndex )
    {
        if ( m_cap->type == CapType::List )
        {
            switch ( m_cap->valueType )
            {
            case CapValueType::Int:
                {
                    IntListCap* listCap = ( IntListCap* ) m_cap;
                    INT32_TO_NPVARIANT( listCap->currentIndex, *result );
                }
                break;
            case CapValueType::Float:
                {
                    FloatListCap* listCap = ( FloatListCap* ) m_cap;
                    DOUBLE_TO_NPVARIANT( ( ( double ) listCap->currentIndex ), *result );
                }
                break;
            }
        }
        else
            return false;
    }
    else if ( name == npid.defaultIndex )
    {
        if ( m_cap->type == CapType::List )
        {
            switch ( m_cap->valueType )
            {
            case CapValueType::Int:
                {
                    IntListCap* listCap = ( IntListCap* ) m_cap;
                    INT32_TO_NPVARIANT( listCap->defaultIndex, *result );
                }
                break;
            case CapValueType::Float:
                {
                    FloatListCap* listCap = ( FloatListCap* ) m_cap;
                    DOUBLE_TO_NPVARIANT( ( ( double ) listCap->defaultIndex ), *result );
                }
                break;
            }
        }
        else
            return false;
    }
    else if ( name == npid.item || name == npid.value )
    {
        if ( m_cap->type == CapType::OneValue )
        {
            switch ( m_cap->valueType )
            {
            case CapValueType::Bool:
                {
                    BoolValueCap* valueCap = ( BoolValueCap* ) m_cap;
                    BOOLEAN_TO_NPVARIANT( valueCap->item, *result );
                }
                break;
            case CapValueType::Int:
                {
                    IntValueCap* valueCap = ( IntValueCap* ) m_cap;
                    INT32_TO_NPVARIANT( valueCap->item, *result );
                }
                break;
            case CapValueType::Float:
                {
                    FloatValueCap* valueCap = ( FloatValueCap* ) m_cap;
                    DOUBLE_TO_NPVARIANT( ( ( double ) valueCap->item ), *result );
                }
                break;
            }
        }
        else
            return false;
    }
    else if ( name == npid.items || name == npid.values )
    {
        if ( m_cap->type == CapType::List )
        {
            if ( !m_npoArray )
            {
                ListBaseCap* listBaseCap = ( ListBaseCap* ) m_cap;

                NPObject* npoArray;

                NPVariant npvArray;

                if ( !::NPN_Invoke( m_npp, m_pPlugin->m_npoWindow, npid.Array /*NPN_GetStringIdentifier( "Array" )*/, NULL, 0, &npvArray ) )
                    return false;

                npoArray = NPVARIANT_TO_OBJECT( npvArray );

                NPVariant npvResult;
                size_t count = listBaseCap->count;

                for( size_t i = 0; i < count; i++ )
                {
                    NPVariant arg;

                    // set argument value
                    switch ( m_cap->valueType )
                    {
                    case CapValueType::Bool:
                        {
                            BOOLEAN_TO_NPVARIANT( ( ( BoolListCap* ) m_cap )->items[ i ], arg );
                        }
                        break;
                    case CapValueType::Int:
                        {
                            INT32_TO_NPVARIANT( ( ( IntListCap* ) m_cap )->items[ i ], arg );
                        }
                        break;
                    case CapValueType::Float:
                        {
                            DOUBLE_TO_NPVARIANT( ( ( double ) ( ( FloatListCap* ) m_cap )->items[ i ] ), arg );
                        }
                        break;
                    }

                    if ( !::NPN_Invoke( m_npp, npoArray, npid.push /*NPN_GetStringIdentifier( "push" )*/, &arg, 1, &npvResult ) )
                        return false;

                    ::NPN_ReleaseVariantValue( &npvResult );
                }

                m_npoArray = npoArray;

                //NPN_RetainObject( m_npoArray );
            }

            ::NPN_RetainObject( m_npoArray );

            OBJECT_TO_NPVARIANT( m_npoArray, resultValue );
        }
        else
            return false;
    }

    return true;
}

ScriptableDeviceCapability::ScriptableDeviceCapability( NPP npp )
    : NPObjectBase( npp ),
    m_npoArray( NULL )
{
}

ScriptableDeviceCapability::~ScriptableDeviceCapability()
{
    if ( m_npoArray )
    {
        NPN_ReleaseObject( m_npoArray );
    }
    if ( m_cap )
    {
        delete m_cap;
    }
}
